package net.siufung.core.utils.select;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

import javax.annotation.Nonnull;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 分支结果选择器
 * @author 陈建峰
 * @since 2022/8/12 4:02 下午
 */
@RequiredArgsConstructor
public class Selector<P, T> {

    /**
     * 被选择
     */
    @Getter
    private boolean selected = false;

    /**
     * 工厂
     */
    private Function<P, T> factory;

    /**
     * 选择器参数，该参数会在进行条件判断和结果获取时会被当做条件传入
     */
    @Nonnull
    private final P params;

    /**
     * 使用指定的参数创建选择器
     * @param params 参数
     * @param <P>   参数类型
     * @param <T>   返回值类型
     * @return 返回新的选择器
     */
    public static <P, T> Selector<P, T> params(P params) {
        return new Selector<>(params);
    }

    /**
     * 传入一个新的分支，如果这个分支满足条件
     * @param branch 则当前选择器将接受当前分支的结果并完成
     * @return 选择器自身
     */
    public Selector<P, T> test(Branch<P, T> branch) {
        if (!selected) {
            boolean pass = branch.tester().test(params);
            if (pass) {
                selected = true;
                factory = branch.factory();
            }
        }
        return this;
    }

    /**
     * 获取结果，如果当前选择器没有击中任何条件分支，则从给定的提供者中获取结果；
     * 否则将使用当前选择器选中的分支
     *
     * @param supplier 默认值提供者
     * @return 如果有分支被击中，则返回分支值，否则返回参数提供的值
     */
    public T or(Supplier<T> supplier) {
        return selected ? this.factory.apply(params) : supplier.get();
    }

    /**
     * @param t 给定默认值
     * @return 如果有分支被击中，则返回分支值，否则返回参数
     * @see #or(Supplier)
     */
    public T or(T t) {
        return or(() -> t);
    }



}
